package com.ikas.ai.server.common.parser;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.ikas.ai.server.common.parser.model.FlowMetaData;
import com.ikas.ai.server.common.parser.model.StepDetailMetaData;
import com.ikas.ai.server.common.parser.model.StepMetaData;
import com.ikas.ai.server.common.parser.model.WorkFlowMetaData;
import com.ikas.ai.server.module.condition.dto.WorkConditionFlowConfigDTO;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Description: 工况流程转换解析器
 * @Author: qi.yilai
 * @Date: 2023/4/11 18:00
 * @Version: 1.0.0
 **/
public class JSONWorkFlowParser {

    private static final String NAME = "name";
    private static final String MACHINE_ID = "machine_id";
    private static final String MACHINE_NO = "machine_no";
    private static final String CURR_WC = "curr_wc";
    private static final String NEXT_WC = "next_wc";
    private static final String DATA = "data";
    private static final String VALID_METE_VALUE = "valid_mete_value";
    private static final String IGNORE = "ignore";

    private static final String FROM_STEP = "from_step";
    private static final String TO_STEP = "to_step";
    private static final String TIMEOUT = "timeout";
    private static final String CONDITIONS = "conditions";
    private static final String LABELS = "labels";
    private static final String LABEL = "label";
    private static final String ACTIONS = "actions";
    private static final String TYPE = "type";
    private static final String LABEL_TYPE = "label_type";
    private static final String METES = "metes";
    private static final String METE_NAME = "mete_name";
    private static final String METE_CODE = "mete_code";
    private static final String START_METE = "start_mete";
    private static final String START_METE_NAME = "start_mete_name";
    private static final String END_METE = "end_mete";
    private static final String END_METE_NAME = "end_mete_name";
    private static final String SORT = "sort";
    private static final String GROUPS = "groups";
    private static final String GROUP_NO = "group_no";
    private static final String P_METE_CODES = "p_mete_codes";

    private static final String SUBS = "subs";
    private static final String LOGICAL_OPERATOR = "logic_operator";

    private static final String SINGLE = "single";
    private static final String COMPOSITE = "composite";

    private static final String UPDATE_POLICY = "update_policy";

    private static final String EARLY_CACHE = "early_cache";

    /**
     * 解析工况元数据
     *
     * @param source
     * @return
     */
    public static WorkFlowMetaData parse(String source) {
        JSONObject rootJsonObject = JSONObject.parseObject(source);
        String name = rootJsonObject.getString(NAME);
        Long machineId = rootJsonObject.getLong(MACHINE_ID);
        String machineNo = rootJsonObject.getString(MACHINE_NO);
        String currentWc = rootJsonObject.getString(CURR_WC);
        String nextWc = rootJsonObject.getString(NEXT_WC);
        String flowMeteName = rootJsonObject.getString(METE_NAME);
        String flowMeteCode = rootJsonObject.getString(METE_CODE);
        String flowValidMeteValue = (String) rootJsonObject.getOrDefault(VALID_METE_VALUE, "1");
        List<String> startMete = rootJsonObject.getJSONArray(START_METE).toJavaList(String.class);
        List<String> startMeteName = rootJsonObject.getJSONArray(START_METE_NAME).toJavaList(String.class);
        List<String> endMete = rootJsonObject.getJSONArray(END_METE).toJavaList(String.class);
        List<String> endMeteName = rootJsonObject.getJSONArray(END_METE_NAME).toJavaList(String.class);
        JSONArray dataArray = rootJsonObject.getJSONArray(DATA);

        FlowMetaData flowMetaData = FlowMetaData.builder().wfName(name).machineId(machineId).machineNo(machineNo)
                .currWc(currentWc).nextWc(nextWc).meteName(flowMeteName).meteCode(flowMeteCode).validMeteValue(flowValidMeteValue).startMete(startMete).startMeteName(startMeteName)
                .endMete(endMete).endMeteName(endMeteName).build();
        List<StepMetaData> steps = Lists.newArrayList();
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject jsonObject = dataArray.getJSONObject(i);
            String stepName = jsonObject.getString(FROM_STEP);
            int timeout = jsonObject.getInteger(TIMEOUT);
            String stepMeteName = jsonObject.getString(METE_NAME);
            String stepMeteCode = jsonObject.getString(METE_CODE);
            String validMeteValue = (String) jsonObject.getOrDefault(VALID_METE_VALUE, "1");
            Integer stepSort = jsonObject.getInteger(SORT);
            Integer type = jsonObject.getInteger(TYPE);
            StepMetaData stepMetaData = StepMetaData.builder().step(stepName).defaultDelay(timeout).meteName(stepMeteName).meteCode(stepMeteCode).validMeteValue(validMeteValue).sort(stepSort).type(type).build();

            //处理分组
            JSONArray groups = jsonObject.getJSONArray(GROUPS);
            List<StepDetailMetaData> details = Lists.newArrayList();
            for (int j = 0; j < groups.size(); j++) {
                JSONObject group = groups.getJSONObject(j);
                Integer groupNo = group.getInteger(GROUP_NO);
                String toStep = group.getString(TO_STEP);

                // 解析条件(响应项)
                JSONObject conditionObj = group.getJSONObject(CONDITIONS);
                details.add(parseStepDetailsForCondition(groupNo, toStep, conditionObj));

                // 解析labels
                JSONArray labels = group.getJSONArray(LABELS);
                if (Objects.nonNull(labels)) {
                    details.addAll(parseStepDetailsForLabels(groupNo, toStep, labels));
                }
            }
            stepMetaData.setDetails(details);

            // 解析执行命令(执行项)
            JSONObject actionObj = jsonObject.getJSONObject(ACTIONS);
            stepMetaData.getDetails().addAll(parseStepDetailsForAction(actionObj));

            steps.add(stepMetaData);
        }
        return WorkFlowMetaData.builder().flowMetaData(flowMetaData).stepMetaData(steps).build();
    }

    public static WorkFlowMetaData parseData(WorkConditionFlowConfigDTO config) {
        String source = JSON.toJSONString(config);
        JSONObject rootJsonObject = JSONObject.parseObject(source);
        JSONArray dataArray = rootJsonObject.getJSONArray(DATA);
        List<StepMetaData> steps = Lists.newArrayList();
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject jsonObject = dataArray.getJSONObject(i);
            String stepName = jsonObject.getString(FROM_STEP);
            Integer timeout = jsonObject.getInteger(TIMEOUT);
            String stepMeteName = jsonObject.getString(METE_NAME);
            String stepMeteCode = jsonObject.getString(METE_CODE);
            String validMeteValue = String.valueOf(jsonObject.getOrDefault(VALID_METE_VALUE, 1));
            Integer stepSort = jsonObject.getInteger(SORT);
            Integer type = jsonObject.getInteger(TYPE);
            StepMetaData stepMetaData = StepMetaData.builder().step(stepName).defaultDelay(timeout).meteName(stepMeteName).meteCode(stepMeteCode).validMeteValue(validMeteValue).sort(stepSort).type(type).build();

            //处理分组
            JSONArray groups = jsonObject.getJSONArray(GROUPS);
            List<StepDetailMetaData> details = Lists.newArrayList();
            for (int j = 0; j < groups.size(); j++) {
                JSONObject group = groups.getJSONObject(j);
                Integer groupNo = group.getInteger(GROUP_NO);
                String toStep = group.getString(TO_STEP);

                // 解析条件(响应项)
                JSONObject conditionObj = group.getJSONObject(CONDITIONS);
                details.add(parseStepDetailsForCondition(groupNo, toStep, conditionObj));

                // 解析labels
                JSONArray labels = group.getJSONArray(LABELS);
                if (Objects.nonNull(labels)) {
                    details.addAll(parseStepDetailsForLabels(groupNo, toStep, labels));
                }
            }
            stepMetaData.setDetails(details);

            // 解析执行命令(执行项)
            JSONObject actionObj = jsonObject.getJSONObject(ACTIONS);
            if (actionObj != null) {
                stepMetaData.getDetails().addAll(parseStepDetailsForAction(actionObj));
            }

            steps.add(stepMetaData);
        }
        return WorkFlowMetaData.builder().stepMetaData(steps).build();
    }

    /**
     * 解析条件步骤详情
     *
     * @param jsonObject
     * @return
     */
    private static StepDetailMetaData parseStepDetailsForCondition(Integer groupNo, String groupToStep, JSONObject jsonObject) {
        List<StepDetailMetaData> details = Lists.newArrayList();
        JSONArray jsonArray = jsonObject.getJSONArray(METES);
        if (Objects.nonNull(jsonArray)) {
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject meteObj = jsonArray.getJSONObject(i);
                String meteName = meteObj.getString(METE_NAME);
                String meteCode = meteObj.getString(METE_CODE);
                Integer updatePolicy = meteObj.getInteger(UPDATE_POLICY);
                Integer earlyCache = meteObj.getInteger(EARLY_CACHE);
                String validMeteValue = String.valueOf(meteObj.getOrDefault(VALID_METE_VALUE, 1));
                Integer labelType = 1;
                Integer sort = meteObj.getInteger(SORT);
                Map<String, List<String>> pMeteCodes = new HashMap<>();
                if (meteObj.containsKey(P_METE_CODES)) {
                    pMeteCodes = (Map<String, List<String>>) JSONObject.parse(meteObj.getJSONObject(P_METE_CODES).toJSONString());
                }

                StepDetailMetaData stepDetailMetaData = StepDetailMetaData.builder().meteCode(meteCode).validMeteValue(validMeteValue).meteName(meteName).pMeteCodes(pMeteCodes).type((byte) 1).leaf(true).labelType(labelType)
                        .sort(sort).groupNo(groupNo).groupToStep(groupToStep).earlyCache(earlyCache).updatePolicy(updatePolicy).build();
                details.add(stepDetailMetaData);
            }
        }
        JSONArray subArray = jsonObject.getJSONArray(SUBS);
        // 有可能是单层
        if (Objects.nonNull(subArray)) {
            for (int i = 0; i < subArray.size(); i++) {
                JSONObject subObj = subArray.getJSONObject(i);
                details.add(parseStepDetailsForCondition(groupNo, groupToStep, subObj));
            }
        }

        if (details.size() == 1) {
            return details.get(0);
        } else {
            String logicalOperator = jsonObject.getString(LOGICAL_OPERATOR);
            StepDetailMetaData stepDetailMetaData = StepDetailMetaData.builder().subDetails(details)
                    .subLogicalOperator(logicalOperator).leaf(false).labelType(1).type((byte) 1).groupNo(groupNo).groupToStep(groupToStep).build();
            details.stream().forEach(d -> {
                d.setPDetail(stepDetailMetaData);
            });
            return stepDetailMetaData;
        }
    }

    /**
     * 解析动作步骤
     *
     * @param jsonObject
     * @return
     */
    private static List<StepDetailMetaData> parseStepDetailsForAction(JSONObject jsonObject) {
        List<StepDetailMetaData> details = Lists.newArrayList();
        JSONArray jsonArray = jsonObject.getJSONArray(SINGLE);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject meteObj = jsonArray.getJSONObject(i);
            String meteName = meteObj.getString(METE_NAME);
            String meteCode = meteObj.getString(METE_CODE);
            String validMeteValue = String.valueOf(meteObj.getOrDefault(VALID_METE_VALUE, 1));
            Integer updatePolicy = meteObj.getInteger(UPDATE_POLICY);
            Integer earlyCache = meteObj.getInteger(EARLY_CACHE);
            Integer labelType = 1;
            Integer sort = meteObj.getInteger(SORT);
            Map<String, List<String>> pMeteCodes = new HashMap<>();
            if (meteObj.containsKey(P_METE_CODES)) {
                pMeteCodes = (Map<String, List<String>>) JSONObject.parse(meteObj.getJSONObject(P_METE_CODES).toJSONString());
            }
            StepDetailMetaData stepDetailMetaData = StepDetailMetaData.builder().meteName(meteName).pMeteCodes(pMeteCodes).meteCode(meteCode).validMeteValue(validMeteValue).type((byte) 0).leaf(true).labelType(labelType).updatePolicy(updatePolicy).earlyCache(earlyCache).sort(sort).build();
            details.add(stepDetailMetaData);
        }
        JSONArray compositeArray = jsonObject.getJSONArray(COMPOSITE);
        if (Objects.nonNull(compositeArray)) {
            for (int i = 0; i < compositeArray.size(); i++) {
                JSONObject obj = compositeArray.getJSONObject(i);
                JSONArray dataArray = obj.getJSONArray(DATA);

                List<StepDetailMetaData> composites = Lists.newArrayList();
                for (int j = 0; j < dataArray.size(); j++) {
                    JSONObject meteObj = dataArray.getJSONObject(j);
                    String meteName = meteObj.getString(METE_NAME);
                    String meteCode = meteObj.getString(METE_CODE);
                    String validMeteValue = String.valueOf(meteObj.getOrDefault(VALID_METE_VALUE, 1));
                    Integer updatePolicy = meteObj.getInteger(UPDATE_POLICY);
                    Integer earlyCache = meteObj.getInteger(EARLY_CACHE);
                    Integer labelType = (Boolean) meteObj.getOrDefault(IGNORE, false) ? 4 : 1;
                    Integer sort = meteObj.getInteger(SORT);
                    Map<String, List<String>> pMeteCodes = new HashMap<>();
                    if (meteObj.containsKey(P_METE_CODES)) {
                        pMeteCodes = (Map<String, List<String>>) JSONObject.parse(meteObj.getJSONObject(P_METE_CODES).toJSONString());
                    }

                    StepDetailMetaData stepDetailMetaData = StepDetailMetaData.builder().meteName(meteName).pMeteCodes(pMeteCodes).meteCode(meteCode).validMeteValue(validMeteValue).type((byte) 0).leaf(true).updatePolicy(updatePolicy).earlyCache(earlyCache).labelType(labelType).sort(sort).build();
                    composites.add(stepDetailMetaData);
                }
                String logicalOperator = obj.getString(LOGICAL_OPERATOR);
                StepDetailMetaData sdm = StepDetailMetaData.builder().subDetails(composites)
                        .subLogicalOperator(logicalOperator).leaf(false).labelType(1).type((byte) 0).build();
                details.add(sdm);
                composites.stream().forEach(d -> {
                    d.setPDetail(sdm);
                });
            }
        }
        return details;
    }

    private static List<StepDetailMetaData> parseStepDetailsForLabels(Integer groupNo, String groupToStep, JSONArray jsonArray) {
        List<StepDetailMetaData> details = Lists.newArrayList();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            Integer labelType = jsonObject.getInteger(LABEL_TYPE);
            Byte type = jsonObject.getByte(TYPE);
            if (labelType == 2 || labelType == 3 || labelType == 1) {
                // 2=无测点,仅描述,3=无测点,虚线框
                String label = jsonObject.getString(LABEL);
                StepDetailMetaData stepDetailMetaData = StepDetailMetaData.builder().groupNo(groupNo).groupToStep(groupToStep).labelType(labelType).type(type).label(label).build();
                details.add(stepDetailMetaData);
            }
        }
        return details;
    }
}
